package com.yahoo.labs.snow.util;

import cern.colt.function.IntIntDoubleFunction;
import cern.colt.matrix.impl.SparseDoubleMatrix2D;
import cern.jet.math.Functions;

public class MatrixUtils {

	/**
	 * Modifies a matrix to make it symmetric, by making w(a,b) := max( w(a,b), w(b,a) ).
	 * @param matrix
	 * @return 
	 */
	public static void ensureSymmetric(final SparseDoubleMatrix2D matrix) {
		if( matrix.rows() != matrix.columns() ) {
			throw new IllegalArgumentException("Input should be a square matrix");
		}
		
		for(int u=0; u<matrix.rows(); u++ ) {
			for(int v=0; v<matrix.rows(); v++ ) {
				if( matrix.getQuick(u,v) < matrix.getQuick(v,u) ) {
					matrix.setQuick(u,v,matrix.getQuick(v,u));
				}
			}
		}for(int u=0; u<matrix.rows(); u++ ) {
			for(int v=0; v<matrix.rows(); v++ ) {
				if( matrix.getQuick(u,v) < matrix.getQuick(v,u) ) {
					matrix.setQuick(u,v,matrix.getQuick(v,u));
				}
			}
		}
	}
	
	/**
	 * Counts the number of non-zero elements in a matrix.
	 * 
	 * @param matrix the input matrix.
	 * @return the number of non-zero elements.
	 */
	public static int countNonZeros(final SparseDoubleMatrix2D matrix) {
		int count = 0;
		for(int u=0; u<matrix.rows(); u++ ) {
			for(int v=0; v<matrix.columns(); v++ ) {
				if( matrix.getQuick(u,v) > 0.0 ) {
					count++;
				}
			}
		}
		return count;
	}
	
	/**
	 * Returns the maximum value in a matrix.
	 * 
	 * @param matrix the input matrix.
	 * @return the maximum value.
	 */
	public static double max(final SparseDoubleMatrix2D matrix) {
		return matrix.aggregate(Functions.max, Functions.max(Double.NEGATIVE_INFINITY));
	}

	/**
	 * Multiplies each element of a matrix by a scalar.
	 * 
	 * @param matrix the input matrix
	 * @param multiplier the scalar to multiply by
	 */
	public static void scalarMultiply(SparseDoubleMatrix2D matrix, final double multiplier) {
		matrix.forEachNonZero(new IntIntDoubleFunction() {
			@Override
			public double apply(int i, int j, double val) {
				return val * multiplier;
			}});
	}
	
	

}
